/**
 * 跨操作系统统一接口 单元测试程序
 */
#include <stdio.h>

#include "unios.h"
#include "utils.h"

#include "log.h"
#define LOGLEVEL LOG_DEBUG
#define LOGTAG   "unios"
#include "log4app.h"

#define ASSERT(exp) do {                       \
	if(!(exp)) {                               \
		printf("ASSERT failed: %s\r\n", #exp); \
        goto _final;                           \
	}                                          \
} while (0)

//
// 测试 unios_lock_t
//
static int test_lock() {
    unios_lock_t lock = NULL;
    ASSERT(unios_lock_init(&lock, 1) == STD_ERR_OK);
    ASSERT(unios_lock(lock, 3000) == STD_ERR_OK);
    ASSERT(unios_lock(lock, 0) == STD_ERR_TIMEOUT);
    ASSERT(unios_lock(lock, 1000) == STD_ERR_TIMEOUT);
    ASSERT(unios_unlock(lock) == STD_ERR_OK);
    ASSERT(unios_lock(lock, 1000) == STD_ERR_OK);
    ASSERT(unios_unlock(lock) == STD_ERR_OK);
_final:
    unios_lock_destroy(&lock);
    return 0;
}

//
// 测试 unios_critical_section_t
//
static unios_critical_section_t _cs = NULL;

static void thread_func_test_critical_section(void *cookie) {
    printf("%s %p running ...\n", (const char*)cookie, unios_thread_this());
    std_err_t err;

    ASSERT((err = unios_critical_section_enter(_cs, 1000)) == STD_ERR_OK);
    unios_ms_delay(1000);
    ASSERT(unios_critical_section_leave(_cs) == STD_ERR_OK);

_final:
    // test_cs1: err == STD_ERR_OK
    // test_cs2: err == STD_ERR_TIMEOUT
    printf("%s %p exit: %s\n", (const char*)cookie, unios_thread_this(), std_err_name(err));
}

static int test_critical_section() {
    unios_thread_t thread = NULL;
    ASSERT(unios_critical_section_init(&_cs) == STD_ERR_OK);
    ASSERT(unios_critical_section_enter(_cs, 0) == STD_ERR_OK);
    ASSERT(unios_critical_section_leave(_cs) == STD_ERR_OK);
    ASSERT(unios_thread_create(thread_func_test_critical_section, "test_cs1", UNIOS_THREAD_PRIORITY_DEFAULT, 4096, 0x0F, &thread) == STD_ERR_OK);
    ASSERT(unios_thread_create(thread_func_test_critical_section, "test_cs2", UNIOS_THREAD_PRIORITY_TIME_CRITICAL, 4096, 0xF0, &thread) == STD_ERR_OK);

    unios_ms_delay(3000);

    ASSERT(unios_critical_section_enter(_cs, 1000) == STD_ERR_OK);
    ASSERT(unios_critical_section_leave(_cs) == STD_ERR_OK);

_final:
    return 0;
}

//
// 测试 unios_event_t
//
static unios_event_t _event = NULL;

static void thread_func_test_event(void *cookie) {
    printf("%s %p running ...\n", (const char*)cookie, unios_thread_this());
    std_err_t err = unios_event_wait(_event, 1000);
    // test_event1: err == STD_ERR_OK
    // test_event2: err == STD_ERR_TIMEOUT
    printf("%s %p exit: %s\n", (const char*)cookie, unios_thread_this(), std_err_name(err));
}

static int test_event() {    
    unios_thread_t thread = NULL;
    ASSERT(unios_event_init(&_event, false, false) == STD_ERR_OK);
    ASSERT(unios_thread_create(thread_func_test_event, "test_event1", UNIOS_THREAD_PRIORITY_DEFAULT, 4096, 0x0F, &thread) == STD_ERR_OK);
    unios_event_set(_event, true);
    ASSERT(unios_thread_create(thread_func_test_event, "test_event2", UNIOS_THREAD_PRIORITY_TIME_CRITICAL, 4096, 0xF0, &thread) == STD_ERR_OK);
    
_final:
    return 0;
}

//
// test_main
//
int unios_test_main(int argc, const char **argv) {
    printf("cpu_core_count: %llu\n", (FMTLLU)unios_get_cpu_core_count());

    ASSERT(test_lock() == 0);
    ASSERT(test_critical_section() == 0);
    ASSERT(test_event() == 0);

    puts("Press ENTER to stop ...");
    getchar();

_final:
    unios_critical_section_destroy(&_cs);
    unios_event_destroy(&_event);
    return 0;
}
